﻿using System;
using System.Collections.Generic;

namespace Chimp.Core
{
    public enum StrandType
    {
        SetList,If,ElseIF,Else,End,Transient,App,State,Event,Meth,CallMeth,SetVar,Expr,Value,Constant,CIF,CELSE,CEND,CELSEIF,OR,GetList,DebugList,
        DebugMessage
    }
    public class UseUI : JointNode
    {
        public UseUI(JointNode p)
        {
            SetData(p);
        }
        public override void ParseNode ( )
        {
            Name = GetTok();
        }
        public override void WriteOutput ( )
        {
            l("UIDoc.UseDoc(\""+Name+"\");\n\n");
        }
    }
    public class JointBasic : JointNode
    {
        public class DebugMessage : JointNode
        {
            public Expr Msg = null;
            public DebugMessage(JointNode p)
            {
                
                SetData(p);

            }
            public override void WriteOutput ( )
            {
                w("Console.WriteLine(");
                Msg.WriteOutput();
                l(");");
            }
            public override void ParseNode ( )
            {
                if ( PeekTok ( ) == "DebugMessage" ) GetTok();
                Msg = ParseExpr() as Expr;

            }

        }
        public class BeginTransient : JointNode
        {
             
            public BeginTransient(JointNode n)
            {
                SetData(n);
            }
            public override void WriteOutput ( )
            {

                l("BeginTransient(new " + Name + "(this));");

            }
            public override void ParseNode ( )
            {
            
               if(PeekTok()=="BeginTransient")
               {
                   GetTok();
               }
                Name = GetTok();
                return;

            }
        }
        public class CallMeth : JointNode
        {
            public List<string> Parts = new List<string>();
            public string MethName { get; set; }
            public List<Expr> Pars = new List<Expr>();
            public Var AV { get; set; }
            public CallMeth(JointNode p)
            {
                Name = "CallMeth";
                MethName = "";
                SetData(p);
            }
            public override void WriteOutput ( )
            {
                foreach(var p in Parts)
                {
                    w(p);

                }
                w("(");
                foreach(var e in Pars)
                {
                    e.WriteOutput();
                    if(e!=Pars[Pars.Count-1])
                    {
                        w(" , ");
                    }
                }
                l(");");
            }
            public override void ParseNode ( )
            {
                //base.ParseNode ( );
                while(!Eof)
                {
                    bool done = false;
                    var t = PeekTok();
                    switch(t)
                    {
                        case ".":
                            GetTok();
                            Parts.Add(".");
                            break;
                        case "(":
                            done = true;
                            break;
                        default:
                            GetTok();
                            Parts.Add(t);
                            break;
                    }
                    if ( done ) break;
                }
               
                if(PeekTok()=="(")
                {
                    GetTok();
                    while(!Eof)
                    {
                        var t = PeekTok();
                        switch(t)
                        {
                            case "(":

                                Pars.Add(new Expr(this));
                                break;
                            case ")":
                                GetTok();
                                return;
                            case ",":
                                GetTok();
                                break;
                            default:
                                Console.WriteLine("Malformed Method Call:" + t);
                                return;
                        }

                    }
                }
            }
        }    
        public class IF : JointNode
        {
            public Expr IfExpr = null;
            public IF ElseIf = null;
            public JointBasic IfCode = null;
            public JointBasic ElseCode = null;
            public IF(JointNode p)
            {

                Name = "If";
                SetData(p);

            }
            public override void WriteOutput ( )
            {
                w("     if(");
                IfExpr.WriteOutput();
                w(" )\n{\n");
                IfCode.WriteOutput();
                w("}");
                if(ElseIf!=null)
                {
                    w("else ");
                    ElseIf.WriteOutput();

                }else if(ElseCode!=null)
                {
                    l("");
                    w("else{");
                    ElseCode.WriteOutput();
                    w("}");
                }

            }
            public override void ParseNode ( )
            {
                IfExpr = new Expr(this);
                IfCode = new JointBasic(this);

                var t = PeekTok();
                switch (t)
                {
                    case "CallMeth":


                        break;
                    case "ElseIf":
                        if (ElseCode != null)
                        {
                            Console.WriteLine("Can not ElseIf after a Else construct");
                            return;
                        }
                        ElseIf = new IF(this);
                        break;
                    case "Else":
                        ElseCode = new JointBasic(this);
                        break;
                }

            }
        }
        public List<JointNode> Order = new List<JointNode>();
        public List<string> Output = new List<string>();
        public bool Stub = false;
        public JointBasic(JointNode n)
        {
            Stub = true;
            SetData(n);
        }
        public JointBasic(string name, JointNode n)
            : base(name, n)
        {
            Stub = false;
        }

        public string CodeName { get; set; }

        public string nl(string t)
        {
            if (_cw == null)
            {
                _cw = Parent._cw;
            }
            _cw.WriteLine(t);
            return t;
        }
        public string SmartTok()
        {
            int i = _i;
            while(!Eof)
            {

                var t = GetTok();
                switch(t)
                {
                    case "Create":
                        _i = i;
                        return "Create";
                    case "=":
                        _i = i;
                        return "SetVar";
                    case "(":
                        _i = i;
                        return "CallMeth";
                    case "SetList":
                        _i = i;
                        return "SetList";
                    case "If":
                        _i = i;
                        return "If";
                    case "BeginTransient":
                        _i = i;
                        return "BeginTransient";
                    case "StopTransient":
                        _i = i;
                        return "StopTransient";
                    case "DebugMessage":
                        _i = i;
                        return "DebugMessage";
                    case "End":
                        _i = i;
                        return t;
                    case "UseUI":
                        _i = i;
                        return t;
                    default:
                        break;
                }

            }
            return "End";
        }
        public override void ParseNode()
        {
            while (!Eof)
            {
                string t = SmartTok();

                switch (t)
                {
                    case "UseUI":
                        GetTok();
                        Order.Add(new UseUI(this));
                        break;
                    case "BeginTransient":

                        var bt1 = new BeginTransient(this);
                        Order.Add(bt1);

                        break;
                    case "CallMeth":

                        Console.WriteLine("CallMeth="+PeekTok());
                        var cm1 = new CallMeth(this);

                        Order.Add(cm1);
                        break;
                    case "If":

                        GetTok();
                        var if1 = new IF(this);

                        Order.Add(if1);

                        break;
                    case "SetVar":
                        //GetTok();
                        //string vn = GetTok();


                        //Console.WriteLine("SetVar:" + vn);

                        //if (!Parent.Vars.ContainsKey(vn))
                        //{
                         //   Console.WriteLine("Var:" + vn + " not found within state.");
                        //    return;
                        //}
                       // Var svv = Parent.Vars[vn];

                        var sv = new SetVar(this);
                        Order.Add(sv);

                        break;

                    case "SetList":
                        GetTok();
                        string l = GetTok();

                        Console.WriteLine("SetList " + l);

                        if (!Parent.Vars.ContainsKey(l))
                        {
                            Console.WriteLine("List:" + l + " not found in state.");
                        }
                        Var lv = Parent.Vars[l];
                        var dl = new DataList(lv, this);
                        Order.Add(dl);

                        break;
                    case "Call":


                        break;
                    case "DebugMessage":

                        Order.Add(new DebugMessage(this));

                        break;
                    case "Else":
                        return;
                    case "ElseIf":
                        return;
                        break;
                    case "End":
                        GetTok();
                        //nl("}");
                        return;
                    default:
                        GetTok();
                        //Console.WriteLine("Basic-Syntax Error. Tok:" + t);
                        return;
                }
               
            }
        }

        public override void WriteOutput()
        {
            if ( !Stub )
            {
                nl("public override void " + Name + "()");
                nl("{");
            }

            Console.WriteLine("Order:" + Order.Count);
            foreach (JointNode n in Order)
            {
                n.WriteOutput();
            }
            if ( !Stub )
            {
                nl("}");
            }
        }
    }
}